/**
 * Sql	18/10/2002
 *
 * Lizardo Rios Villavicencio
 *
 * Permite usar sentencias SQL
 *
 */
package agb.Conexion;


//import java.sql.Date;
//import java.sql.Date;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

//import java.text.ParseException;
//import java.util.Vector;
//import java.util.Date;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.me.codigo.Baldor;

/**
 *
 * @author Victor Balta
 */
public class Sql {
    private static boolean estadoConexion = false;
    private static Connection cn = null;
    private static String sSQL = null;
    private static String msgDriver = null;
    //private static Connection conn = null;
    private static boolean estadoError = false;
    private static String nombreError = "";
    
    // constructor
    public Sql() {
        setEstadoConexion(conecta());       //conexion cliente servidor
        //setEstadoConexion(conecta(conn)); //pool de conexiones
    }
    public Sql(boolean opcion){
        if (opcion) {
            // para establecer o pasar la conexion
        }
    }
    
    public static void setConexion(Connection _cn) {
        cn = _cn;
    }
        
    //---------------- Operaciones sql basicas --------------------------//
    // Ejecuta Insert, Delete y Update. Retorna null si todo bien, caso 
    //contrario, el mensaje de error
    public static boolean conecta() {  // conexion cliente - servidor
        cn = (Connection) Conexion.getConexion();
        return (Boolean) (cn == null) ? false : true;
    }
    
    public static boolean conecta(Connection conn) {   // conexion con pool de conexiones
        cn = (Connection) conn;
        return (Boolean) (cn == null) ? false : true;
    }
    
    public static String ejecuta(String sql) {
        String mensaje = null;
        try {
            //ConectaDB, conexiones para la desktop
            //Conecta, conexiones para la web
            //cn = (Connection) Conecta.getConnection();
            //conectado = (Boolean) conecta();
            if (cn == null) {
                mensaje = "No hay conexion a la base de datos...!";
            } else {
                Statement st = cn.createStatement();
                st.execute(sql);
                st.close();
                //cn.close();
            }
            setEstadoError(false);
        } catch (SQLException e) {
            mensaje = e.getMessage().toString();
            setNombreError(mensaje);
            setEstadoError(true);
        } catch (Exception e) {
            mensaje = e.getMessage().toString();
            setNombreError(mensaje);
            setEstadoError(true);
        }

        return mensaje;
    }
    
     public static boolean getEstadoError() {
        return Sql.estadoError;
    }
    public static void setEstadoError(boolean estadoError) {
        Sql.estadoError = estadoError;
    }

    public static void setEstadoConexion(boolean estado) {
        estadoConexion = estado;
    }
    
    public static boolean getEstadoConexion() {
        return estadoConexion;
    }
    
    public static Connection getConexion() {
        return (Connection) cn;
    }
    
    public static void setMensajeDriver(String _msgDriver) {
        msgDriver = _msgDriver;
    }
    public static String getMensajeDriver() {
        return (String) msgDriver;
    }
    
    public static boolean getEstadoPool() {
        return (cn == null) ? false : true;
    }
    
    public static void desconectarse() {
        String mensaje = "";
        try {
            if (!cn.isClosed()) {
                cn.close();
                cn = null;
            }
        } catch (SQLException e) {
            mensaje = e.getMessage().toString();
            setNombreError(mensaje);
            setEstadoError(true);
        } catch (Exception e) {
            mensaje = e.getMessage().toString();
            setNombreError(mensaje);
            setEstadoError(true);
        }
    }
    
    // Ejecuta Select simple
    public ArrayList consulta(String sql) {
        ArrayList regs = new ArrayList();
        //String error = null;

        try {
            if (cn == null) {
                regs = null;
            } else {
                Statement st = cn.createStatement();
                ResultSet rs = st.executeQuery(sql);
                ResultSetMetaData rm = rs.getMetaData();
                int numCols = rm.getColumnCount();

                // Toma los titulos de las columnas
                String[] titCols = new String[numCols];
                for (int i = 0; i < numCols; ++i) {
                    titCols[i] = rm.getColumnName(i + 1);
                // la fila 0 del vector lleva los t�tulos de las columnas
                }
                regs.add(titCols);

                // toma las filas de la consulta
                while (rs.next()) {
                    String[] reg = new String[numCols];

                    for (int i = 0; i < numCols; i++) {
                        reg[i] = rs.getString(i + 1);
                    }
                    regs.add(reg);
                }
                rs.close();
                st.close();
                //cn.close();
            }
            setEstadoError(false);
        } catch (SQLException e) {
            regs = null;
            setNombreError(e.getMessage().toString());
            setEstadoError(true);
        } catch (Exception e) {
            regs = null;
            setNombreError(e.getMessage().toString());
            setEstadoError(true);
        }
        return regs;
    }
//---------------- Fin de operaciones sql basicas ---------------------//
    
//-------------  Operaciones sql con consultas preparadas  ------------//  
    public static String ejecuta(String sql, int[] tipos, String[] campos) {
        String mensaje = null;
        try {
            if (cn == null) {
                mensaje = "No hay conexion a la base de datos...!";
            } else {
                PreparedStatement l_pstm = cn.prepareStatement(sql);
                // Recorre por campo y su tipo, preparando la consulta
                for (int i=1; i<=campos.length; i++) 
                    l_pstm = consultaPreparada(l_pstm, tipos, i, campos);
                setSQL(l_pstm.toString());
                l_pstm.execute();
                l_pstm.close();
                cn.commit(); 
                //cn.close();
            }
            setEstadoError(false);
        } catch (SQLException e) {
            mensaje = e.getMessage().toString();
            setNombreError(mensaje);
            setEstadoError(true);
        } catch (Exception e) {
            mensaje = e.getMessage().toString();
            setNombreError(mensaje);
            setEstadoError(true);
        }
        return mensaje;
    }

// Ejecuta Select con consultas preparadas
    public static ArrayList consulta(String sql, int[] tipos, String[] campos) {
        ArrayList regs = new ArrayList();

        try {
            if (cn == null) {
                regs = null;
            } else {
                PreparedStatement l_pstm = cn.prepareStatement(sql);
                // Recorre por campo y su tipo, preparando la consulta
                for (int i=1; i<=campos.length; i++)
                    l_pstm = consultaPreparada(l_pstm, tipos, i, campos);
                setSQL(l_pstm.toString());
                
                ResultSet rs = l_pstm.executeQuery();
                ResultSetMetaData rm = rs.getMetaData();
                int numCols = rm.getColumnCount();

                // Toma los titulos de las columnas
                String[] titCols = new String[numCols];
                for (int i = 0; i < numCols; ++i) {
                    titCols[i] = rm.getColumnName(i + 1);
                    // la fila 0 del vector lleva los t�tulos de las columnas
                }
                regs.add(titCols);

                // toma las filas de la consulta
                while (rs.next()) {
                    String[] reg = new String[numCols];

                    for (int i = 0; i < numCols; i++) {
                        reg[i] = rs.getString(i + 1);
                    }
                    regs.add(reg);
                }
                rs.close();
                l_pstm.close();
                //cn.close();
            }
            setEstadoError(false);
        } catch (SQLException e) {
            // implementar errores en mensajes capturados
            regs = null;
            setNombreError(e.getMessage().toString());
            setEstadoError(true);
        } catch (Exception e) {
            regs = null;
            setNombreError(e.getMessage().toString());
            setEstadoError(true);
        }
        return regs;
    }    
    
    // Retorna una sola fila
    public String[] getFila(String sql) {
        ArrayList lista = consulta(sql);
        String[] fila = null;

        if (lista != null) { // todo OK!
            if (lista.size() > 1) // hay filas
                fila = (String[]) lista.get(1);    // en 0 estan los titulos
        }
        return fila;
    }
    
    public static String[] getFila(ArrayList lista) {
        String[] fila = null;

        if (lista != null) { // todo OK!
            if (lista.size() > 1) // hay filas
                fila = (String[]) lista.get(1);    // en 0 estan los titulos
        }
        return fila;
    }

    // Retorna un solo campo
    public String getCampo(String sql) {
        String[] fila = getFila(sql);
        String campo = null;

        if (fila != null) // hay campo
            campo = fila[0];
        return campo;
    }

    // Retorna autonumerico
    public int getAutoNumerico(String nombreTabla) {
        String sql = "SELECT MAX(secuencia) FROM secuencias WHERE nombre_tabla = '" + nombreTabla + "'";
        String[] fila = getFila(sql);
        int intCodigo = 0;
        String strFila = null;
        String resultado = null;

        if (fila != null) {
            strFila = fila[0];
            intCodigo = Baldor.aEntero(strFila) + 1;
            sql = "UPDATE secuencias SET secuencia = " + intCodigo + " WHERE nombre_tabla = '" + nombreTabla + "'";
        } else {
            intCodigo = 1;
            sql = "INSERT INTO secuencias VALUES(1,'" + nombreTabla + "',NULL,true)";
        }
        resultado = ejecuta(sql);
        if (resultado != null) 
            logs(resultado);

        return intCodigo;
    }

    // Historial de Bitacora
    public static void logs(String error) {
        String sql = "INSERT INTO bitacora VALUES('" + error.toString() + "')";
        ejecuta(sql);
    }
    
    // Clase PreparedSatament
    private static PreparedStatement consultaPreparada(PreparedStatement l_pstm, 
                                         int[] tipos, 
                                         int i, 
                                         String[] campos) throws SQLException {
        switch (tipos[i-1]) {
            case 1://Boolean
                l_pstm.setBoolean(i, Baldor.aBooleano(campos[i-1]));
                break;
            case 2://Byte
                l_pstm.setByte(i, Baldor.aByte(campos[i-1]));
                break;
            case 3://Date
                try {
                    String sFecha = campos[i-1];
                    java.util.Date fecha = (java.util.Date)Baldor.aFecha(sFecha);
                    l_pstm.setDate(i, (java.sql.Date) fecha);
                } catch (ParseException ex) {
                    Logger.getLogger(Sql.class.getName()).log(Level.SEVERE, null, ex);
                }
                //l_pstm.setDate(i, campos[i-1]);
                break;
            case 4://Double
                l_pstm.setDouble(i, Baldor.aReal(campos[i-1]));
                break;
            case 5://Float
                l_pstm.setFloat(i, Baldor.aFlotante(campos[i-1]));
                break;
            case 6://Int
                l_pstm.setInt(i, Baldor.aEntero(campos[i-1]));
                break;    
            case 7://Long
                l_pstm.setLong(i, Baldor.aEnteroLargo(campos[i-1]));
                break;    
            case 8://String
                l_pstm.setString(i, campos[i-1]);
                break;    
            case 9://Time
                l_pstm.setTime(i, Baldor.aTiempo(campos[i-1]));
                break;    
        }
        return (PreparedStatement) l_pstm;
    }
    
    public static void setSQL(String sSQL){
        Sql.sSQL = sSQL;
    }
    public static String getSQL() {
        return Sql.sSQL;
    }
    
    public static void setNombreError(String nombreError) {
        Sql.nombreError = nombreError;
    }
    public static String getNombreError() {
        return Sql.nombreError;
    }
    
}
